<?php
//
// +------------------------------------------------------------------------+
// | Gecko Framework                                                        |
// +------------------------------------------------------------------------+
//
require_once( 'Gecko/Template/Exception.php' );

/**
 * Template parser
 *
 * @package Gecko
 * @author Christopher Valderrama <gatorv@gmail.com>
 * @copyright Copyright (c) 2007-2008
 * @version $Id$
 * @access public
 */
class Gecko_Template {
	private static $jsLibraries = array(); //@var private static array Array of JavaScript Libraries to include
	private static $jsHelperLibraries = array(); //@var private static array Array of JavaScript modules to include
	private static $_params = array(
		"hasLayout" => true,
		"pageTitle" => "",
		"body" => "",
	); // @var private static Static array of template params to render
	private static $_cache = array(); //@var private static array Cached templates for faster rendering
	private static $_helpers = array(
		"core",
		"html",
		"javascript",
		"form",
	); //@var private static array of loaded Template Helpers
	private static $_templateRepository = ''; //@var private static string Directory of templates
	private static $_templateLayout = ''; //@var private static string Main Layout to render template
	private static $_helpersLoaded = false;

	/**
	 * Registers a Javascript Library to use in templates
	 *
	 * @param string $lib Library to use
	 * @access public static
	 * @return void
	 **/
	public static function registerLibrary( $lib ) {
		$jslib = "<script type=\"text/javascript\" src=\"$lib\"></script>";
		if( !in_array( $jslib, self::$jsLibraries ) ) {
			self::$jsLibraries[] = $jslib;
		}
	}

	/**
	 * Use a JavaScript Library in templates
	 *
	 * @param string $lib Library to use
	 * @access public static
	 * @return void
	 **/
	public static function useHelper( $lib ) {
		$found = false;
		$assetsDir = Gecko_Router::ASSETS_DIR;

		$lib = "<script type=\"text/javascript\" src=\"$assetsDir/JavaScriptHelpers/$lib\"></script>";

		foreach( self::$jsHelperLibraries as $theLib ) {
			if( $lib == $theLib ) {
				$found = true;
			}
		}

		if( !$found )
			self::$jsHelperLibraries[] = $lib;
	}

	/**
	 * Returns all JavaScript libraries registered
	 *
	 * @access public static
	 * @retun array
	 **/
	public static function getJavascriptLibs() {
		return array_merge( self::$jsLibraries, self::$jsHelperLibraries );
	}

	/**
	 * Register a View (template) helper to parse data
	 *
	 * @param string $helper The Helper to register
	 * @access public static
	 * @return void
	 **/
	public static function registerViewHelpers( $helper ) {
		self::$_helpers[] = $helper;
	}

	/**
	 * Use a specific Layout to render the template
	 *
	 * @param string $template
	 * @access public static
	 * @return void
	 **/
	public static function useLayout( $template ) {
		self::$_templateLayout = $template;
	}

	/**
	 * Sets a custom Param to use in the View Template
	 *
	 * @param string $name
	 * @param mixed $value
	 * @access public static
	 * @return void
	 **/
	public static function setParam( $name, $value ) {
		self::$_params[$name] = $value;
	}

	/**
	 * Pushes a already set parameter and adds a value to it
	 *
	 * @param string $name
	 * @param mixed $value
	 * @access public static
	 * @return void
	 **/
	public static function pushParam( $name, $value ) {
		if( !isset( self::$_params[$name] ) ) self::$_params[$name] = array();

		self::$_params[$name][] = $value;
	}

	/**
	 * Returns a custom set Parameter
	 *
	 * @access public static
	 * @return mixed
	 **/
	public static function getParam( $name ) {
		return (isset( self::$_params[$name] ) ? self::$_params[$name] : null);
	}

	/**
	 * Sets the directory where templates are loaded
	 *
	 * @param string $dir
	 * @access public static
	 * @return void
	 **/
	public static function setTemplateDir( $dir ) {
		if( !is_string( $dir ) ) {
			throw new Gecko_Template_Exception( '$dir is expected to be a string, ' . gettype( $dir ) . ' given' );
		}

		self::$_templateRepository = $dir;
	}

	/**
	 * This functions parses the data and renders the template, it's
	 * called from inside the controller
	 *
	 * @param string $template the Template to render
	 * @param array $data The Template data
	 * @access public static
	 * @return string the parsed template
	 **/
	public static function controllerRender( $template, $data ) {
		$output = Gecko_Template::renderTemplate( $template, $data  );

		if( Gecko_Template::getParam( 'hasLayout' ) === true ) {
			self::setParam( 'body', $output );
			$output = "";
			$output = Gecko_Template::page();
		}

		return $output;
	}

	/**
	 * Finds if a template exists
	 *
	 * @param string $template
	 * @return boolean
	 * @access public static
	 **/
	public static function templateExists( $template ) {
		$baseDir = Zend_Registry::get('baseDir');
		$template_dir = $baseDir . "/tpl/";
		if( !empty( self::$_templateRepository ) )
			$template_dir .= self::$_templateRepository . "/";

		$tpl = $template_dir . $template . ".php";

		return file_exists( $tpl );
	}

	/**
	 * Open and parses a template file, and fills the data
	 *
	 * @param string $template The Template
	 * @param array $data The Template Data
	 * @param boolean $standalone
	 **/
	public static function renderTemplate( $template, $data, $standalone = false ) {
		if( $standalone ) {
			$tpl = $template;
		} else {
			$baseDir = Zend_Registry::get('baseDir');
			$template_dir = $baseDir . "/tpl/";
			if( !empty( self::$_templateRepository ) ) {
				$template_dir .= self::$_templateRepository . "/";
			}

			$tpl = $template_dir . $template . ".php";
			Gecko_Template::loadHelpers();
		}

		if( file_exists( $tpl ) ) {
			extract( $data, EXTR_OVERWRITE );
			ob_start();
			include( $tpl );
			$result = ob_get_clean();
		} else {
			throw new Gecko_Template_Exception( $template . " template doesn't exists" );
		}

		return $result;
	}

	/**
	 * Load the registered helpers into the template scope
	 *
	 * @access public static
	 * @return void
	 **/
	public static function loadHelpers() {
		$baseDir = Zend_Registry::get('baseDir');
		$helperDir = Gecko_Router::LIBRARY_DIR . "/Template/Helpers/";
		$helperAppDir = $baseDir . "/application/helpers/";

		$helpers = array_unique(self::$_helpers);

		foreach( self::$_helpers as $helper ) {
			$file = $helperDir . $helper . "Helper.php";
			if( file_exists( $file ) ) { // Load From Library
				include_once( $file );
			} else {
				$file = $helperAppDir . $helper . "Helper.php";
				if( file_exists( $file ) ) { // Load from Application Helper Dir
					include_once( $file );
				} else {
					throw new Gecko_Template_Exception( "$file application helper, file not found!" );
				}
			}
		}
	}

	/**
	 * Renders text into the Main Page Template
	 *
	 * @return string
	 **/
	public static function page() {
		$baseDir = Zend_Registry::get('baseDir');
		$cfg = Zend_Registry::get("config");
		$mainLayout = $baseDir . $cfg->Template->main;

		if( !empty( self::$_templateLayout ) ) {
			$template_html = $baseDir . "/tpl/";
			if( !empty( self::$_templateRepository ) ) {
				$template_html .= self::$_templateRepository . "/";
			}

			$template_html .= self::$_templateLayout;
		} elseif( !empty( $mainLayout ) ) {
			$template_html = $mainLayout;
		} else {
			throw new Gecko_Template_Exception("No Main Template defined, define one in config.xml, or register a custom one");
		}

		if( !file_exists( $template_html ) ) {
			throw new Gecko_Template_Exception( "Template defined not found! " . $template_html );
		}

		ob_start();
		include( $template_html );
		$main = ob_get_clean();

		return $main;
	}

	/**
	 * Returns a JavaScript tag with data escaped
	 *
	 * @param string $code
	 * @param public static
	 * @return string
	 **/
	public static function getJavaScriptTag( $code ) {
		$return = "<script type=\"text/javascript\">\n";
		$return.= "//<![CDATA[\n";
		$return.= $code;
		$return.= "//]]>\n";
		$return.= "</script>";

		return $return;
	}
}
?>